package nature.nano.control.script.assembly;

import java.util.HashMap;
import java.util.Map;

import nature.nano.component.Strings;
import nature.nano.component.part.Combiner;
import nature.nano.environment.Config;
import nature.nano.iface.Accepter;
import nature.nano.iface.Props;
import nature.nano.iface.enumer.EnumStringCallback;
import nature.nano.iface.secondary.Configable;
import nature.nano.iface.secondary.SlotBoard;
import nature.nano.classinfo.ClassInfoLib;

class ClassStaticInfo {

	private ClassInfoLib clazzs = ClassInfoLib.instance();
	
	private Object object;
	private Map<String, Combiner> combiners = new HashMap<String, Combiner>();
	
	public ClassStaticInfo(String name, Props propsProp) {
		object = clazzs.newInstance(name);
		if (object == null) {
			return;
		}
		configObject(name, object, propsProp);
	}

	public ClassStaticInfo(Object object) {
		this.object = object;
	}

	public boolean valid() {
		return object != null;
	}


	public Object getObject() {
		return object;
	}

	public boolean plug(String slot, ClassStaticInfo next) {
		if (!(object instanceof SlotBoard) || !(next.object instanceof Accepter)) {
			return false;
		}
		
		SlotBoard board = (SlotBoard) object;
		Combiner combiner = combiners.get(slot);
		Accepter accepter = (Accepter) next.object;
		
		if (combiner != null) {
			if (next.object instanceof Accepter) {
				combiner.add(accepter);
			}
			return true;
		}
		
		Accepter old = board.plug(slot, accepter);
		if (old != null) {
			Combiner newCombiner = new Combiner(old, accepter);
			board.plug(slot, newCombiner);
			combiners.put(slot, newCombiner);
		} else {
			Accepter plugged = board.plug(slot, accepter);
			if (plugged != accepter) {
				return false;
			}
		}
		
		return true;
	}

	private static void configObject(String name, Object object, Props propsProp) {
		if (!(object instanceof Configable)) {
			return;
		}
		
		Configable configable = (Configable) object;
		
		configObjectBase(name, configable);
		
		if (propsProp != null) {
			if (propsProp.get(Strings.anonymous + 0) != null) {
				replacePropByAnonymousProp(configable, propsProp);
			} else {
				replacePropByProp(configable, propsProp);			
			}
		}
	}
	
	private static void configObjectBase(final String name, final Configable configable) {
		configable.enumProp(
			new EnumStringCallback() {
				public void onRead(String key) {
					String value = Config.current().getDefaultValue(key);
					
					String replacer = Config.current().getDefaultValue(name + Strings.period + key);
					if (replacer != null) {
						value = replacer;
					}
					
					if (value != null) {
						configable.setProp(key, value);
					}
				}
			});			
	}
	
	private static void replacePropByAnonymousProp(final Configable configable, final Props propsProp) {
		final int[] index = new int[1];
		index[0] = 0;
		configable.enumProp(
			new EnumStringCallback() {
				public void onRead(String key) {
					String replacer = propsProp.get(Strings.anonymous + index[0]);
					if (replacer != null) {
						configable.setProp(key, replacer);
					}
					index[0]++;
				}
			});	
	}

	private static void replacePropByProp(final Configable configable, final Props propsProp) {
		configable.enumProp(
			new EnumStringCallback() {
				public void onRead(String key) {
					String replacer = propsProp.get(key);
					if (replacer != null) {
						configable.setProp(key, replacer);
					}
				}
			});	
	}

	public String getDefaultSlot() {
		if (!(object instanceof SlotBoard)) {
			return null;
		}
		return getSlot((SlotBoard) object);
	}

	private static String getSlot(SlotBoard board) {
		if (board.slotCount() != 2) {
			return null;
		}
		final String[] slot = new String[1];
		board.enumSlot(
			new EnumStringCallback() {
				public void onRead(String data) {
					if (!data.equals(Strings.error)) {
						slot[0] = data;
					}
				}
			});
		return slot[0];
	}
}
